import { getLength } from 'ol/sphere';
import LineString from 'ol/geom/LineString';
import Point from 'ol/geom/Point';
import Polygon from 'ol/geom/Polygon';
import { containsXY } from 'ol/extent';

/**
 * 计算两点之间的距离（以公里为单位）
 * @param point1 点1的坐标 [lon, lat]
 * @param point2 点2的坐标 [lon, lat]
 * @returns 距离（公里）
 */
export function calculateDistance(point1: [number, number], point2: [number, number]): number {
  const line = new LineString([point1, point2]);
  // 使用OpenLayers的球面距离计算
  const distance = getLength(line);
  return distance / 1000; // 转换为公里
}

/**
 * 判断点是否在多边形内
 * @param point 点坐标 [lon, lat]
 * @param polygon 多边形坐标 [[lon1, lat1], [lon2, lat2], ...]
 * @returns 是否在多边形内
 */
export function isPointInPolygon(point: [number, number], polygon: number[][]): boolean {
  // 确保多边形至少有3个点
  if (polygon.length < 3) {
    return false;
  }

  // 创建多边形并判断点是否在其中
  const poly = new Polygon([polygon]);
  return poly.intersectsCoordinate(point);
}

/**
 * 使用射线法计算点是否在多边形内（备用方法）
 * @param point 点坐标 [lon, lat]
 * @param polygon 多边形坐标 [[lon1, lat1], [lon2, lat2], ...]
 * @returns 是否在多边形内
 */
export function isPointInPolygonRayCasting(point: [number, number], polygon: number[][]): boolean {
  const x = point[0];
  const y = point[1];
  let inside = false;
  
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    const xi = polygon[i][0];
    const yi = polygon[i][1];
    const xj = polygon[j][0];
    const yj = polygon[j][1];
    
    const intersect = ((yi > y) !== (yj > y)) && 
        (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    
    if (intersect) {
      inside = !inside;
    }
  }
  
  return inside;
}

/**
 * 计算点到多边形的最短距离
 * @param point 点坐标 [lon, lat]
 * @param polygon 多边形坐标 [[lon1, lat1], [lon2, lat2], ...]
 * @returns 最短距离（公里）
 */
export function calculateDistanceToPolygon(point: [number, number], polygon: number[][]): number {
  // 如果多边形点数不足，返回无穷大距离
  if (polygon.length < 3) {
    return Infinity;
  }

  // 使用两种方法检查点是否在多边形内
  if (isPointInPolygon(point, polygon) || isPointInPolygonRayCasting(point, polygon)) {
    return 0;
  }

  // 计算点到多边形每条边的最短距离
  let minDistance = Infinity;
  
  for (let i = 0; i < polygon.length; i++) {
    const start = polygon[i];
    const end = polygon[(i + 1) % polygon.length]; // 循环到第一个点，闭合多边形
    
    // 计算点到线段的最短距离
    const distance = calculateDistanceToLineSegment(point, start, end);
    
    if (distance < minDistance) {
      minDistance = distance;
    }
  }
  
  return minDistance;
}

/**
 * 计算点到线段的最短距离
 * @param point 点坐标 [lon, lat]
 * @param lineStart 线段起点 [lon, lat]
 * @param lineEnd 线段终点 [lon, lat]
 * @returns 最短距离（公里）
 */
function calculateDistanceToLineSegment(
  point: [number, number], 
  lineStart: number[], 
  lineEnd: number[]
): number {
  const x = point[0];
  const y = point[1];
  const x1 = lineStart[0];
  const y1 = lineStart[1];
  const x2 = lineEnd[0];
  const y2 = lineEnd[1];
  
  // 线段长度的平方
  const lengthSquared = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);
  
  // 如果线段长度为0，则计算点到起点的距离
  if (lengthSquared === 0) {
    return calculateDistance(point, [x1, y1] as [number, number]);
  }
  
  // 计算点在线段上的投影位置参数 t
  let t = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / lengthSquared;
  t = Math.max(0, Math.min(1, t));
  
  // 计算最近点坐标
  const nearestX = x1 + t * (x2 - x1);
  const nearestY = y1 + t * (y2 - y1);
  
  // 计算点到最近点的距离
  return calculateDistance(point, [nearestX, nearestY] as [number, number]);
}

/**
 * 确定船舶图标类型（基于与电子围栏的距离）
 * @param point 船舶坐标 [lon, lat]
 * @param fencePolygons 电子围栏多边形数组 [[[lon1, lat1], [lon2, lat2], ...], ...]
 * @returns 图标类型: 'red', 'yellow', 'green'
 */
export function determineShipIconType(
  point: [number, number], 
  fencePolygons: number[][][]
): 'red' | 'yellow' | 'green' {
  // 默认使用绿色图标（距离围栏2公里以外）
  let iconType: 'red' | 'yellow' | 'green' = 'green';
  
  // 遍历所有电子围栏
  for (const polygon of fencePolygons) {
    // 多边形验证
    if (!polygon || polygon.length < 3) {
      continue;
    }
    
    // 使用两种方法检查点是否在多边形内
    const inPolygon = isPointInPolygon(point, polygon) || isPointInPolygonRayCasting(point, polygon);
    
    // 如果点在任一围栏内，使用红色图标
    if (inPolygon) {
      return 'red';
    }
    
    // 计算点到围栏的距离
    const distance = calculateDistanceToPolygon(point, polygon);
    
    // 如果距离小于2公里但不在围栏内，使用黄色图标
    if (distance < 2) {
      iconType = 'yellow';
      // 不立即返回，因为还需要检查是否在其他围栏内
    }
  }
  
  return iconType;
} 